package cn.shiwei.order.service.impl;

import cn.shiwei.basic.exception.MyException;
import cn.shiwei.basic.service.impl.BaseServiceImpl;
import cn.shiwei.basic.util.LoginContextUtil;
import cn.shiwei.order.domain.OrderAddress;
import cn.shiwei.order.domain.OrderDetail;
import cn.shiwei.order.domain.OrderPet;
import cn.shiwei.order.dto.OrderDto;
import cn.shiwei.order.mapper.OrderAddressMapper;
import cn.shiwei.order.mapper.OrderDetailMapper;
import cn.shiwei.order.mapper.OrderPetMapper;
import cn.shiwei.order.service.IOrderPetService;
import cn.shiwei.pay.domain.PayBill;
import cn.shiwei.pay.service.IPayBillService;
import cn.shiwei.pet.domain.Pet;
import cn.shiwei.pet.mapper.PetMapper;
import cn.shiwei.quartz.job.OrderExpireJob;
import cn.shiwei.quartz.service.IQuartzService;
import cn.shiwei.shopcart.domain.ShopCart;
import cn.shiwei.shopcart.mapper.ShopCartMapper;
import cn.shiwei.shopcart.service.impl.ShopCartServiceImpl;
import cn.shiwei.user.domain.UserAddress;
import cn.shiwei.user.mapper.UserAddressMapper;
import cn.shiwei.user.mapper.UserMapper;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.time.DateUtils;
import org.assertj.core.util.DateUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class OrderPetServiceImpl extends BaseServiceImpl<OrderPet> implements IOrderPetService {

    @Autowired
    private OrderPetMapper orderPetMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private PetMapper petMapper;

    @Autowired
    private IQuartzService quartzService;

    @Autowired
    private ShopCartMapper shopCartMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private IPayBillService payBillService;

    @Autowired
    private UserAddressMapper userAddressMapper;

    @Autowired
    private OrderAddressMapper orderAddressMapper;

    @Autowired
    private ShopCartServiceImpl shopCartServiceImpl;

    @Override
    @Transactional
    public String saveOrder(Map<String, Long> map) {
        Long petId = map.get("petId");
        Long addId = map.get("addId");
        Long payId = map.get("payId");

        // 参数校验, 判断参数非空
        if (petId == null || addId == null || payId == null){
            throw new MyException("非法访问");
        }

        // 用户地址校验
        UserAddress uadd = userAddressMapper.loadById(addId);
        if (uadd == null) {
            throw new MyException("用户地址为空");
        }
        Pet pet = null;
        // 宠物pet表库存减一
        synchronized (this) {
            // 校验petId对应的宠物是否上架
            // 保证pet每次线程都是最新查出的, 并立即使库存减一
            pet = petMapper.loadPetAndDetailByIDState(petId, Pet.ON_SALE_STATUS);
            if (pet == null && Pet.ON_SALE_STATUS.equals(pet.getState())) {
                throw new MyException("非法访问");
            }

            // 加锁防止高并发, 防止超卖
            if (pet.getRepertory() <= 0 || pet.getRepertory() == null){
                throw new MyException("所在地区商品无货, 尽情期待");
            }
            // 下订单就减库存
            pet.setRepertory(pet.getRepertory() - 1);
            petMapper.update(pet);
        }

        // 创建保存订单----------------------------------------------------
        Long uid = userMapper.loadByLogininfoId(LoginContextUtil.getLoininfo().getId()).getId();
        // Long pet_id, Long user_add_id, Long pay_type, Integer state, BigDecimal price, Integer total, Long userId

        // 设置订单生成时间 // 默认在domain中
        // 设置订单过期时间 // 默认在domain中
        // 设置商品数量 // 默认1, 在domain
        OrderPet orderPet = new OrderPet(
                // 设置宠物id
                petId,
                // 设置用户地址
                uadd.getId(),
                // 设置支付方式
                payId,
                // 设置订单状态
                OrderPet.STATUS_PENDING_PAYMENT,
                // 设置金额
                pet.getSaleprice(),
                // 设置用户id
                uid
        );
        //  获取用户的userid保存到订单中
        System.out.println(orderPet);
        orderPetMapper.save(orderPet);
        //保存订单详情--------------------------------------------------
        // String name, String cover, BigDecimal price, Long produck_id, String sn, Long order_id, Long shop_id
        OrderDetail orderDetail = new OrderDetail(
                // 设置商品名称
                pet.getName(),
                // 设置商品封面
                pet.getResources(),
                // 设置价格
                pet.getSaleprice(),
                // 设置单品id
                petId,
                // 设置对应的订单编号sn
                orderPet.getSn(),
                // 设置对应的订单号id
                orderPet.getId(),
                // 设置商品对应的商铺id
                pet.getShop().getId()
        );
        // 保存订单商品详情
        orderDetailMapper.save(orderDetail);
        // 保存下订单的地址-----------------------------------------------------------
        OrderAddress orderAddress = new OrderAddress();
        // 从用户选中的地址useraddrss拷贝数据(拷贝相同地址)
        BeanUtils.copyProperties(uadd, orderAddress);
        // 设置地址对应的订单号
        orderAddress.setOrderSn(orderPet.getSn());
        // 设置对应的订单id
        orderAddress.setOrderId(orderPet.getId());
        orderAddressMapper.save(orderAddress);
        // 生成保存一个支付单------------------------------------------------------
        /**
         Long businessKey,
         String businessType,
         BigDecimal money,
         String title,
         Integer payChannel,
         String unionPaySn,
         Long shopId,
         String shopName
         */
        payBillService.save(
                pet.getId(),
                PayBill.CONSUMPTION_TYPE,
                orderPet.getPrice(),
                "购买宠物: " + pet.getName(),
                payId,
                orderPet.getSn(),
                pet.getShop().getId(),
                pet.getShop().getName()
        );

        // 生成保存一个定时任务------------------------------------------------------
//        Map<Object, Object> hashmap = new HashMap<>();
//        hashmap.put("sn", orderPet.getSn());
//        quartzService.addRoderExpireJob(
//                "orderExpireJob" + orderPet.getTotal(), // 定时任务名字
//                OrderExpireJob.class, // 订单超时处理的工作类
//                // TODO 测试使用超时时间为10s
//                hashmap,
//                DateUtils.addSeconds(orderPet.getCreate_time(), 10)
//        );

        return  orderPet.getSn();
    }

    @Override
    public String saveOrder(OrderDto dto) {
        Long addId = dto.getAddId();
        Long payId = dto.getPayId();
        List<Long> carts = dto.getCarts();

        // 参数校验, 判断参数非空
        if (CollectionUtils.isEmpty(carts) || addId == null || payId == null){
            throw new MyException("非法访问");
        }

        // 用户地址校验
        UserAddress uadd = userAddressMapper.loadById(addId);
        if (uadd == null) {
            throw new MyException("用户地址为空");
        }

        // TODO 此处bug,carts对应的petid不存在也过了,
        Pet pet = null;
        for (Long cartId : carts) {
            ShopCart shopCart = shopCartMapper.loadByIdAndState(cartId, ShopCart.ADD_TO_CART);
            // 宠物pet表减库存
            synchronized (this) {
                // 校验petId对应的宠物是否上架
                // 保证pet每次线程都是最新查出的, 并立即使库存减一
                pet = petMapper.loadPetAndDetailByIDState(shopCart.getProductId(), Pet.ON_SALE_STATUS);
                if (pet == null && Pet.ON_SALE_STATUS.equals(pet.getState())) {
                    throw new MyException("非法访问");
                }
                // 加锁防止高并发, 防止超卖
                if (pet.getRepertory() <= 0 || pet.getRepertory() == null){
                    throw new MyException("所在地区商品无货, 尽情期待");
                }
                pet.setRepertory(pet.getRepertory() - shopCart.getTotal());
                petMapper.update(pet);
            }
        }

        List<ShopCart> shopCarts = shopCartMapper
                .patchLoadByIdAndState(carts, ShopCart.ADD_TO_CART);
        // 获取宠物id
        List<Long> pId = shopCarts
                .stream()
                .map(shopCart ->{
                            Long productId = shopCart.getProductId();
                            return productId;
                }).collect(Collectors.toList());
        // 获取金额
        BigDecimal bigDecimal = shopCartServiceImpl.calCart(carts);
        // 获取用户userid
        Long uid = userMapper.loadByLogininfoId(LoginContextUtil.getLoininfo().getId()).getId();
        OrderPet orderPet = new OrderPet(
                // 设置宠物id // 注意这里这个参数没有意义,
                pId,
                // 设置用户地址
                uadd.getId(),
                // 设置支付方式
                payId,
                // 设置订单状态
                OrderPet.STATUS_PENDING_PAYMENT,
                // 设置金额
                bigDecimal,
                // 设置用户id
                uid
        );
        // 保存订单
        orderPetMapper.save(orderPet);

        //保存订单详情--------------------------------------------------
        List<Pet> pets = petMapper.patchLoad(pId, Pet.ON_SALE_STATUS);
        pets.forEach(petShop -> {
            OrderDetail orderDetail = new OrderDetail(
                    // 设置商品名称
                    petShop.getName(),
                    // 设置商品封面
                    petShop.getResources(),
                    // 设置价格
                    petShop.getSaleprice(),
                    // 设置单品id
                    petShop.getId(),
                    // 设置对应的订单编号sn
                    orderPet.getSn(),
                    // 设置对应的订单号id
                    orderPet.getId(),
                    // 设置商品对应的商铺id
                    petShop.getShop().getId()
            );
            orderDetailMapper.save(orderDetail);
        });

        OrderAddress orderAddress = new OrderAddress();
        // 从用户选中的地址useraddrss拷贝数据(拷贝相同地址)
        BeanUtils.copyProperties(uadd, orderAddress);
        // 设置地址对应的订单号
        orderAddress.setOrderSn(orderPet.getSn());
        // 设置对应的订单id
        orderAddress.setOrderId(orderPet.getId());
        orderAddressMapper.save(orderAddress);

        return orderPet.getSn();
    }
}
